import pygame, sys
import time
from random import randint
from pygame.locals import *

GRAVITY = 8
FLOOR = 500
BOUNCE_LOSS = 0.35
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
MIN_VEL = 0.0
GAP = 3
STEPS = 10
SIZE = 50


def testVCollide(a, b):
    return a > b and a < b + SIZE

def swapVelocities(a,b):
    bVel = a.yVel
    a.yVel = b.yVel
    b.yVel = bVel

def raiseHigher(a,b):
    if a.y < b.y:
        difference = b.y - a.y
        a.y = a.y - SIZE + difference
    else:
        difference = a.y - b.y
        b.y = b.y - SIZE + difference

def handleCollision(a, b, timeD):
    swapVelocities(a,b)
    raiseHigher(a,b)
    
class Game:
    def __init__(self):
        self.window = pygame.display.set_mode((800,600))
        pygame.display.set_caption('Bounce')
        
        self.screen = pygame.display.get_surface()
        
        self.background = pygame.Surface(self.screen.get_size()).convert()
        self.background.fill((50,50,50))

        self.keyHandler = {K_ESCAPE : lambda : sys.exit(0)}
        self.actorPiles = []
        colors = [WHITE, GREEN, BLUE, RED]
        for x in xrange(10):
            xPos = x * SIZE
            actors = []
            for y in xrange(5) :
                actors.append(Actor(xPos, randint(-300,200), colors[randint(0,3)]))
            self.actorPiles.append(actors)
        
    def run(self):
        lastTime = time.time()
        while True:
            currentTime = time.time()
            timeDelta = currentTime - lastTime
            lastTime = currentTime
            self.input(pygame.event.get())
            self.animate(timeDelta)
            self.detectCollide(timeDelta)
            
            self.render()
    
    def animate(self, timeD):
        for actors in self.actorPiles:
            for actor in actors:
                actor.animate(timeD)
    
    def detectCollide(self, timeD):
        for actors in self.actorPiles:
            actorCount = len(actors)
            collision = True
            while collision:
                collision = False
                for index in xrange(actorCount):
                    a = actors[index]
                    b = actors[index-1]
                    if testVCollide(a.y, b.y):
                        collision = True
                        handleCollision(a, b, timeD)
    
    def render(self):
        self.screen.blit(self.background, (0,0))
        for actors in self.actorPiles:
            for actor in actors:
                actor.render(self.screen)
        pygame.display.flip()
    
    def input(self, events):
        for event in events:
            if event.type == QUIT:
                print 'Goodbye!'
                sys.exit(0)
            elif event.type == KEYDOWN:
                try:
                    self.keyHandler[event.key]()
                    self.render()
                except KeyError:
                    print 'key not bound'

class Actor:
    def __init__(self, x, y, color):
        self.x = x
        self.y = y
        self.oldY = y
        self.xVel = 0
        self.yVel = 0
        self.color = color
        self.updatePointsAndRect()
    
    def animate(self, timeD):
        self.yVel = self.yVel + GRAVITY * timeD
        if (self.yVel > 0 and self.yVel < MIN_VEL) or (self.yVel < 0 and self.yVel > -MIN_VEL) :
            self.yVel = 0 
        self.oldY = self.y
        self.y = self.y + self.yVel
        if self.y >= FLOOR:
            self.bounce()
        self.updatePointsAndRect()
        self.lastCollideTime = 0

    def bounce(self):
        self.yVel = self.yVel * - (1- BOUNCE_LOSS)
        self.y = FLOOR - (self.y - FLOOR)

    def updatePointsAndRect(self):
        x = self.x
        y = self.y
        self.pointList = [(x,y),(x+50,y),(x+50,y+50),(x, y+50), (x,y), (x+25, y-10), (x+75, y-10), (x+50, y), (x+50, y+50), (x+75, y+40), (x+75, y-10), (x+50, y)]
        self.rect = pygame.Rect(x,y,50,50)
        

    def render(self, surface):
        pygame.draw.polygon(surface,
             self.color, 
             self.pointList,
             3)
    
    
Game().run();